home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 8 / Night Owl CD-ROM (NOPV8) (Night Owl Publisher) (1993).ISO / 034a / aecur101.arj / CONTRIB / CURSES / SRC / KBBGTASK.C < prev    next >
C/C++ Source or Header  |  1990-03-08  |  6KB  |  248 lines

  1. /*----------------------------------------------------------------------
  2.  *
  3.  *  kbbgtask.c
  4.  *
  5.  *  copyright (c) 1987,88,89,90 J. Alan Eldridge
  6.  *
  7.  *  background tasking keyboard handler for Curses
  8.  *
  9.  *  NOTES:
  10.  *
  11.  *  look, folks, all this does is fake multitasking while
  12.  *  the user is sitting thinking about what to type
  13.  *
  14.  *  there are a maximum of MAX tasks in the queue, and each
  15.  *  task must be a function that takes no args and whose
  16.  *  return value can be ignored
  17.  *
  18.  *  lastly, and most importantly, this thing relies on two basic
  19.  *  concepts:
  20.  *
  21.  *      1.  a user sits there without typing anyting, just
  22.  *          thinking, quite a bit of the time, so DOS sits there are
  23.  *          repeatedly polls the keyboard (twiddling its thumbs)
  24.  *
  25.  *      2.  if i poll the keyboard myself, i can use some time to
  26.  *          do some TRIVIAL (meaning FAST!!) tasks while said user
  27.  *          is ruminating on what key to press next, thereby making
  28.  *          more effective use of available CPU cycles
  29.  *
  30.  *  example use of all this:
  31.  *
  32.  *  int show_time_in_corner();
  33.  *
  34.  *  addbgtask(show_time_in_corner,5); -- add a real time clock, priority 5
  35.  *      so that whenever you're waiting, the time is updated onscreen
  36.  *
  37.  *  now, whenever Curses reads a character, it will go through this
  38.  *  routine kbgetc() and automagically run things for you! anytime
  39.  *  you call getch() or wgetch() etc. you'll come here
  40.  *
  41.  *  BUGS/WARNINGS:
  42.  *
  43.  *      1. a task (obviously!) can't do keyboard input (FIXED 1/90)
  44.  *
  45.  *      2. a task shouldn't mess with other tasks
  46.  *
  47.  *      3.  task ids are assigned in numerical order, and are not reused,
  48.  *          so you can't add more than 32k tasks in a single program run
  49.  *          without risking weirdness (this limit really shouldn't be of
  50.  *          any consequence, since if you add and kill that many tasks you
  51.  *          probably are doing something else wrong that is worse, anyway)
  52.  *
  53.  *      4.  a task should be a short, fast routine or else keyboard
  54.  *          response will be degraded unacceptably
  55.  *
  56.  *----------------------------------------------------------------------
  57.  */
  58.  
  59. #include "curses.h"
  60.  
  61. #define TASK_MAX 32
  62. typedef void (*PFV)();
  63.  
  64. /*----------------------------------------------------------------------
  65.  *
  66.  * the task handler's private storage
  67.  *
  68.  * how many tasks, who is up next, and pointers
  69.  *
  70.  *----------------------------------------------------------------------
  71.  */
  72.  
  73. struct tcb {
  74.     int id,pri,cnt;
  75.     PFV func;
  76. };
  77.  
  78. static int taskcnt = 0, currtask = 0, nextid = 0;
  79. static struct tcb tasktabl[TASK_MAX];
  80.  
  81. /*----------------------------------------------------------------------
  82.  * 
  83.  * static findtask -- look up a task id in the table
  84.  *
  85.  *----------------------------------------------------------------------
  86.  */
  87.  
  88. static int
  89. findtask(id)
  90. int id;
  91. {
  92.     int i;
  93.  
  94.     for (i = 0; i < taskcnt; i++)
  95.         if (tasktabl[i].id == id)
  96.             return i;
  97.     return -1;
  98. }
  99.  
  100. /*----------------------------------------------------------------------
  101.  * 
  102.  * getbgpri -- returns the priority of the task specified
  103.  *
  104.  * BUGS:
  105.  *
  106.  * since it returns -1 on error, there is no way to know if a
  107.  * task is invalid or just not running
  108.  *
  109.  *----------------------------------------------------------------------
  110.  */
  111.  
  112. int
  113. getbgpri(id)
  114. int id;
  115. {
  116.     int n = findtask(id);
  117.  
  118.     return (n >= 0) ? tasktabl[n].pri : -1;
  119. }
  120.  
  121. /*----------------------------------------------------------------------
  122.  * 
  123.  * setbgpri -- given a task id, sets the priority
  124.  *
  125.  * a priority < 0 disables the task from running
  126.  *
  127.  *----------------------------------------------------------------------
  128.  */
  129.  
  130. int
  131. setbgpri(id, pri)
  132. int id, pri;
  133. {
  134.     int n = findtask(id);
  135.  
  136.     if (n >= 0) {
  137.         tasktabl[n].pri = pri;
  138.         return 0;
  139.     }
  140.  
  141.     return -1;
  142. }
  143.  
  144. /*----------------------------------------------------------------------
  145.  *
  146.  * addbgtask -- queues up a task in the scheduler & executes it once
  147.  *
  148.  * returns the task id or -1 if error
  149.  *
  150.  *----------------------------------------------------------------------
  151.  */
  152.  
  153. int
  154. addbgtask(func, pri)
  155. void    (*func)();
  156. int     pri;
  157. {
  158.     if (taskcnt < TASK_MAX) {
  159.         (*func)();
  160.         tasktabl[taskcnt].func = func;
  161.         tasktabl[taskcnt].pri = pri;
  162.         tasktabl[taskcnt].cnt = 0;
  163.         return tasktabl[taskcnt++].id = nextid++;
  164.     }
  165.  
  166.     return -1;
  167. }
  168.  
  169. /*----------------------------------------------------------------------
  170.  *
  171.  * rmvbgtask -- removes a task (unqueues it)
  172.  *
  173.  * returns the number of tasks remaining
  174.  *
  175.  *----------------------------------------------------------------------
  176.  */
  177.  
  178. int
  179. rmvbgtask(id)
  180. int id;
  181. {
  182.     int n = findtask(id);
  183.   
  184.     if (n >= 0 && n < taskcnt) {
  185.         int i;
  186.  
  187.         for (i = n; i < taskcnt - 1; i++)
  188.             tasktabl[i] = tasktabl[i+1];
  189.         if (currtask == n) {
  190.             if (currtask == taskcnt - 1)
  191.                 currtask = 0;
  192.         } else if (currtask > n)
  193.             currtask--;
  194.             return --taskcnt;
  195.     }
  196.  
  197.     return -1;
  198. }
  199.  
  200. /*----------------------------------------------------------------------
  201.  *
  202.  * kbgetc -- poll the keyboard and multitask while waiting
  203.  *           then return a character
  204.  *
  205.  * the static recursion flag lets a task do keyboard input
  206.  * 
  207.  * this should really be reserved for things like error conditions
  208.  * because it is just not a clean way to do things in general
  209.  * 
  210.  * if the key is ctl-backslash, clean up and exit (panic)
  211.  *  
  212.  *----------------------------------------------------------------------
  213.  */
  214.  
  215. static int recurse = 0;
  216.  
  217. int
  218. kbgetc()
  219. {
  220.  
  221.     int c;
  222.         
  223.     if (!recurse) {
  224.         recurse++;
  225.         while (!_kb_look()) {
  226.             if (taskcnt < 1)
  227.                 continue;
  228.             if (tasktabl[currtask].cnt++ >= tasktabl[currtask].pri) {
  229.                 if (tasktabl[currtask].pri >= 0)
  230.                     (*(tasktabl[currtask].func))();
  231.                 tasktabl[currtask].cnt = 0;
  232.             }
  233.             if (++currtask >= taskcnt)
  234.                 currtask = 0;
  235.         }
  236.         recurse--;
  237.     }    
  238.  
  239.     c = _kb_getc();
  240.  
  241.     if (c == K_CTL_BKSLASH) {
  242.         endwin();
  243.         exit(1);
  244.     }
  245.  
  246.     return c;
  247. }
  248.